#ifndef __M_LOPPER_H__
#define __M_LOPPER_H__
/*异步线程消息处理器*/
#include "buffer.hpp"
#include <mutex>
#include <functional>
#include <thread>
#include <memory>
#include <atomic>
#include <condition_variable>
namespace wmhLog
{   
    enum class AsyncSafeType
    {
        AsyncSafeType_Safe,//安全状态
        AsyncSafeType_unSafe,//非安全状态
    };
    using Functor=std::function<void(Buffer& )>;
    class AsyncLopper
    {
    public:    
        using ptr=std::shared_ptr<AsyncLopper>;
        AsyncLopper(const Functor& cb,AsyncSafeType lopper_type=AsyncSafeType::AsyncSafeType_Safe)
            :_stop(false),_thread(std::thread(&AsyncLopper::threadEntry,this)),
            _callBack(cb),_lopper_type(lopper_type)
        {}
        ~AsyncLopper(){
            stop();
        }
        void stop()
        {
            _stop=true;
            _cond_con.notify_all();//唤醒所有的消费者工作线程
            _thread.join();
        }
        void push(const char*data,size_t len)
        {
            //安全：固定大小，缓冲区满则阻塞
            //不安全：无线扩容
            std::unique_lock<std::mutex> lock(_mutex);
            //wait:直到条件为真停止阻塞
            //如果缓冲区剩余可写空间大于len，表示可以添加
            if(_lopper_type==AsyncSafeType::AsyncSafeType_Safe)
                _cond_pro.wait(lock,[&](){return _pro_buf.writeAbleSize()>=len;});
            //满足条件
            _pro_buf.push(data,len);
            //消费线程因为消费缓冲区为空正在阻塞等待，唤醒消费者对缓冲区中的数据进行处理
            _cond_con.notify_all();
        }

    private:
        //线程入口函数,对消费缓冲区数据进行处理，
        void threadEntry()
        {
            while (1)
            {
                //程序刚运行的时候消费者内没有数据，先交换缓冲区
                {
                    //1.判断生产者内有无数据，有则交换，无则阻塞
                    std::unique_lock<std::mutex> lock(_mutex);
                    //退出标志被设置并且生产区没有数据，退出，否则会出现
                    //生产区有数据没有被处理
                    if(_stop && _pro_buf.empty()) break;

                    //有数据，不为空，返回true，停止阻塞
                    //或者是退出前（析构）唤醒
                    _cond_con.wait(lock,[&](){return _stop|!_pro_buf.empty();});

                    _con_buf.swap(_pro_buf);
                    //2.唤醒生产者
                    if(_lopper_type==AsyncSafeType::AsyncSafeType_Safe)
                        _cond_pro.notify_all();
                }
                //3.对消费者内所有的数据进行处理
                _callBack(_con_buf);
                //4.处理完之后，重置消费者缓冲区
                _con_buf.reset();
            }
            
        }
    private:
        Functor _callBack;//具体的回调处理函数，由异步工作器使用者传入

    private:
        AsyncSafeType _lopper_type;//日志器安全模式
        std::atomic<bool> _stop;//工作器停止标志
        Buffer _pro_buf;//生产缓冲区
        Buffer _con_buf;//消费缓冲区
        std::mutex _mutex;
        std::condition_variable _cond_pro;//生产者条件变量
        std::condition_variable _cond_con;//消费者条件变量
        std::thread _thread;//异步工作器对应的工作线程
    };
}






#endif

